package com.vaadin.thomas.contenttool.data;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import com.vaadin.thomas.contenttool.Config;
import com.vaadin.thomas.contenttool.ContentTool;

/**
 * A single Model instance is basically a singleton to a certain data storage
 * location, identified by the {@link Config#getModelId()} and
 * {@link Config#getStorageLocation()} values given in
 * {@link #initialize(Config)}. Any number of {@link ContentTool} instances may
 * connect to a single Model instance.
 * <p>
 * Any Model instance needs to be completely thread-safe!
 * */
public interface Model {

	/**
	 * May only be called from {@link ModelFactory}!
	 * <p>
	 * Called before any other operations.
	 */
	public abstract void init(Config c);

	/**
	 * Get the {@link Config} this model was initialized with
	 */
	public abstract Config getConfig();

	/**
	 * May only be called from {@link ModelFactory}!
	 */
	public abstract void destroy();

	/**
	 * Get all {@link Version}s stored, in order from oldest to newest.
	 * Guaranteed to always return at least 1 version, the preview.
	 */
	public abstract List<Version> getVersions();

	/**
	 * Get all {@link Tag}s registered to the data store.
	 */
	public abstract List<Tag> getTags();

	/**
	 * Get all {@link Value}s for this key, in order from oldest to newest.
	 */
	public abstract List<Value> getAllVersions(String key);

	/**
	 * Always returns the preview version, may never return null;
	 */
	public abstract Version getPreview();

	/**
	 * Creates a new {@link Version} of the given {@link Value}s in the Preview
	 * Version and creates a new Preview.
	 * 
	 * @param copyUnstoredToNew
	 *            If those values that are in the Preview but not in
	 *            <code>valuesToStore</code> should be moved to the new Preview,
	 *            or discarded.
	 * @param valuesToStore
	 *            A collection of all the {@link Value}s that should be a part
	 *            of the new version
	 * @param comitter
	 * @param commitMessage
	 */
	public abstract void commitPreview(boolean copyUnstoredToNew,
			Collection<Value> valuesToStore, String comitter,
			String commitMessage);

	/**
	 * Discards all {@link Value}s in the current Preview {@link Version}.
	 */
	public abstract void discardPreview();

	/**
	 * Adds a new Value without {@link Localization}s into the Preview
	 * {@link Version} if it doesn't already exist.
	 */
	public abstract Value addValue(String key);

	/**
	 * Sets a {@link Value} in the store with the given data. This method
	 * overwrites any previous matching values for the key-locale-start
	 * combination.
	 * 
	 * @param identifier
	 * @param loc
	 * @param value
	 * @param start
	 */
	public abstract void setValue(String key, Locale loc, String value,
			Date start);

	/**
	 * @see #setValue(String, Locale, String, Date)
	 */
	public abstract void setValue(String key, Locale loc, String value);

	/**
	 * Completely discards the given {@link Localization}, if it is connected to
	 * the Preview {@link Version}.
	 * 
	 * @param data
	 */
	public abstract void discardLocalization(Localization data);

	/**
	 * Get production {@link Version}, if it exists.
	 */
	public abstract Version getProduction();

	public abstract boolean isPartOfPreview(Value v);

	public abstract boolean isPartOfPreview(Localization l);

	/**
	 * TODO: move to util?
	 * 
	 * Get unlinked {@link Localization} instance.
	 */
	public abstract Localization createLocalization(Locale loc, String value,
			Date start);

	/**
	 * Get (and create) a {@link Tag} with the given ID.
	 */
	public abstract Tag getTag(String id);

}